package com.taomus.mytools.simplec.compiler;

import java.util.HashMap;
import java.util.Map;
import java.util.Queue;

import org.objectweb.asm.Label;
import org.objectweb.asm.Type;

import com.taomus.mytools.simplec.common.SyntaxTuple;
import com.taomus.mytools.simplec.common.Token;
import com.taomus.mytools.simplec.common.WordEnum;
import com.taomus.mytools.simplec.utils.AsmUtils;
import com.taomus.mytools.simplec.utils.ErrorEnum;
import com.taomus.mytools.simplec.utils.ErrorUtils;
import com.taomus.mytools.simplec.utils.GeneratorAdapterUtils;
import com.taomus.mytools.simplec.utils.ICode;
import static com.taomus.mytools.simplec.common.SyntaxTuple.*;

public class FunctionCompilerNew implements ICode {
	private static class FAdapter {
		private GeneratorAdapterUtils adapter;
		private SyntaxTuple st;

		public FAdapter(GeneratorAdapterUtils adapter, SyntaxTuple st) {
			this.adapter = adapter;
			this.st = st;
		}

		public GeneratorAdapterUtils getGeneratorAdapterUtils() {
			return this.adapter;
		}
		public void setSyntaxTuple(SyntaxTuple st){
			this.st = st;
		}
		public WordEnum opcode() {
			return this.st.getOpCode();
		}

		public Token getT1() {
			return this.st.getToken(T1);
		}

		public Token getT2() {
			return this.st.getToken(T2);
		}

		public Token getT3() {
			return this.st.getToken(T3);
		}
	}

	AsmUtils as;
	Queue<SyntaxTuple> tupleQ;
	Map<String, Integer> localNum = new HashMap<>();
	Map<String, Label> labelMap = new HashMap<>();

	public FunctionCompilerNew(final AsmUtils as, final Queue<SyntaxTuple> q) {
		this.as = as;
		this.tupleQ = q;
	}

	@Override
	public void code(GeneratorAdapterUtils adapter) {
		int fAgrsNum = 0;
		while(true){
			SyntaxTuple st = tupleQ.poll();
			ErrorUtils.error(st);
			WordEnum opcode = st.getOpCode();
			FAdapter adp  = new FAdapter(adapter, st);
			if(opcode == WordEnum.FUNCR){
				break;
			}
			switch(opcode){
			case FAGRSNUM:
				fAgrsNum = funcAgrsNumber(adp);
				break;
			case FRAGRS:
				this.funcAgrs(adp, fAgrsNum);
				break;
			default:
				break;
			}
		}
	}

	/**
	 * 函数参数(实际参数)
	 * @param fadapter
	 * @param fAgrsNum
	 */
	private void funcAgrs(FAdapter fadapter,int fAgrsNum){
		GeneratorAdapterUtils adapter = fadapter.getGeneratorAdapterUtils();
		Token t1 = fadapter.getT1();
		for(int i =0;i<fAgrsNum;i++){
			adapter.push(i);
			if(t1.getCode() == WordEnum.NUMBER){
				adapter.push(Integer.parseInt(t1.getSymbol()));
				adapter.invokeStatic(Integer.class,"Integer valueOf(int)");
				adapter.arrayStore(Type.getType(Object.class));
				if(i+1 != fAgrsNum){
					adapter.dup();
				}
			}else if(t1.getCode() == WordEnum.ID){
				String fieldName = t1.getSymbol();
				switch(t1.getLevel()){
				case 0:
					adapter.loadThis();
					switch(t1.getCode()){
					case _INT:
						adapter.getField(fieldName, int.class);
						adapter.invokeStatic(Integer.class,"Integer valueOf(int)");
						break;
					case _DOUBLE:
						adapter.getField(fieldName, double.class);
						adapter.invokeStatic(Double.class,"Double valueOf(double)");
						break;
					default:
						ErrorUtils.error(ErrorEnum.TYPE_ERROR, t1);
						break;
					}
					adapter.arrayStore(Type.getType(Object.class));
					break;
				default:
					adapter.loadLocal(localNum.get(fieldName), int.class);
					adapter.invokeStatic(Integer.class,"Integer valueOf(int)");
					adapter.arrayStore(Type.getType(Object.class));
					break;
				}
				if(i+1 != fAgrsNum){
					adapter.dup();
				}
			}
			SyntaxTuple temp = tupleQ.peek(); 
			if(temp.getOpCode() == WordEnum.FRAGRS){
				fadapter.setSyntaxTuple(tupleQ.poll());
			}
		}
	}
	
	/**
	 * 函数参数数量
	 */
	private int funcAgrsNumber(FAdapter adapter){
		int fAgrsNum = Integer.parseInt(adapter.getT1().getSymbol());
		GeneratorAdapterUtils gau = adapter.getGeneratorAdapterUtils();
		gau.loadThis();
		gau.push(fAgrsNum);
		gau.newArray(Type.getType(Object.class));
		gau.dup();
		return fAgrsNum;
	}
}
